home *** CD-ROM | disk | FTP | other *** search
- /*
- This program accepts a list of C or C++ source files for a project
- and outputs a dependency list suitable for a Makefile. It
- recursively parses the include files to insure that all
- dependencies are noted. Relative and absolute pathnames for both
- source and include files are correctly handled. Only include lines
- that start with `#include "' are looked at. Commented-out include
- lines are not ignored.
-
- Only dependency lists for the object files corresponding to the
- source files are generated. It is the responsibility of the
- programmer to supply the dependency lists for the desired
- executables and to define $(CC) and $(CFLAGS). If a file called
- `.makeheader' exists in the project directory, the contents of this
- file will be prepended to the output of this program. Thus, if the
- user places user-defined dependencies in this file, the command
-
- deps *.c > Makefile
-
- will correctly create a complete Makefile for a C project.
-
- Written by Keith Pomakis on October 10, 1994. Public Domain.
- */
-
- #include <iostream.h>
- #include <fstream.h>
- #include <string.h>
- #include <time.h>
- #include "../KPbasic.h"
- #include "../KPList.h"
- #include "../KPString.h"
- #include "../KPSet.h"
-
- /****************************************************************************/
-
- KPString progname;
-
- const char *const headerfile = ".makeheader";
-
- template class KPList<KPString>; // Explicit instantiation.
-
- /****************************************************************************/
-
- static inline KPString base(const KPString &string)
- { return string.tokens('/').tail(); }
-
- static inline KPString path(const KPString &string)
- { return string.substr(0, string.length() - base(string).length()); }
-
- static inline bool is_relative(const KPString &string)
- { return string.is_empty() || string[0] != '/'; }
-
- static inline KPString root(const KPString &string)
- { return string.tokens('.').head(); }
-
- static void process_header();
- static void process_source(const KPString &sourcename);
- static bool process_file(const KPString &filename, KPSet<KPString> &includes,
- KPString pathname);
-
- /****************************************************************************/
-
- int
- main(int argc, char *argv[])
- {
- progname = base(argv[0]);
-
- if (argc < 2) {
- cerr << "Usage: " << progname << " -help\n"
- << " " << progname << " <sourcefile> ...\n";
- exit(EXIT_FAILURE);
- }
-
- if (strncmp(argv[1], "-h", 2) == 0) {
- cout <<
- "This program accepts a list of C or C++ source files for a project\n"
- "and outputs a dependency list suitable for a Makefile. It\n"
- "recursively parses the include files to insure that all\n"
- "dependencies are noted. Relative and absolute pathnames for both\n"
- "source and include files are correctly handled. Only include lines\n"
- "that start with `#include \042' are looked at. Commented-out\n"
- "include lines are not ignored.\n\n"
- "Only dependency lists for the object files corresponding to the\n"
- "source files are generated. It is the responsibility of the\n"
- "programmer to supply the dependency lists for the desired\n"
- "executables and to define $(CC) and $(CFLAGS). If a file called\n"
- "`.makeheader' exists in the project directory, the contents of this\n"
- "file will be prepended to the output of this program. Thus, if the\n"
- "user places user-defined dependencies in this file, the command\n\n"
- " " << progname << " *.c > Makefile\n\n"
- "will correctly create a complete Makefile for a C project.\n\n"
- "Written by Keith Pomakis on October 10, 1994. Public Domain.\n";
- exit(EXIT_SUCCESS);
- }
-
- process_header();
-
- time_t current_time = time(NULL);
- cout << "\n###########################################################\n";
- cout << "#\n";
- cout << "# File dependencies generated by \042" << progname << "\042.\n";
- cout << "# " << ctime(¤t_time);
- cout << "#\n";
- cout << "###########################################################\n\n";
-
- for (int i=1; i<argc; i++)
- process_source(argv[i]);
-
- return 0;
- }
-
- /****************************************************************************/
-
- static void
- process_header()
- {
- ifstream stream(headerfile, ios::in);
- if (!stream) return;
-
- KPString line;
-
- while (!stream.eof()) {
- line.read_line(stream);
- if (!stream.eof()) cout << line << '\n';
- }
- }
-
- /****************************************************************************/
-
- static void
- process_source(const KPString &sourcename)
- {
- KPSet<KPString> includes = sourcename;
-
- cout << root(base(sourcename)) << ".o: \\\n";
-
- if (process_file(sourcename, includes, path(sourcename))) {
- KPReadOnlyIterator<KPString> iter(includes.list());
- FOREACH(iter) {
- cout << " " << *iter;
- if (!iter.at_end()) cout << " \\";
- cout << '\n';
- }
- cout << "\t$(CC) $(CFLAGS) -c " << sourcename << "\n\n";
- }
- }
-
- /****************************************************************************/
-
- static bool
- process_file(const KPString &filename, KPSet<KPString> &includes, KPString pathname)
- {
- ifstream stream(filename, ios::in);
- if (!stream) {
- cerr << progname << ": error opening file \042" << filename << "\042\n";
- return false;
- }
-
- KPString line;
-
- while (!stream.eof()) {
- line.read_line(stream);
- if (line.length() > 11 && memcmp(line, "#include \042", 10) == 0) {
- const int second_quote = line.index_of('\042', 10);
- if (second_quote < 0 || second_quote == 10) {
- cerr << progname << ": error in file \042" << filename
- << "\042 - bad include line:\n" << line << '\n';
- return false;
- }
- KPString new_include = line.substr(10, second_quote-10);
- if (is_relative(new_include)) new_include = pathname + new_include;
- if (!includes.contains(new_include)) {
- includes += new_include;
- if (!process_file(new_include, includes, path(new_include)))
- return false;
- }
- }
- }
-
- return true;
- }
-
- /****************************************************************************/
-
-